import logging

from drf_haystack.viewsets import HaystackViewSet
from rest_framework import mixins, status
from rest_framework.decorators import action
from rest_framework.generics import ListAPIView, RetrieveAPIView
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet

from mlh.utils.pagination import StandardResultsSetPagination
from tucao.models import Tucao, Comment, TucaoFollow, CommentFollow, Collections
from tucao.serializers import TucaoSerializer, TucaoDetailSerializer, CommentSerializer, TucaoFollowSerializer, \
    TucaoSelectSerializer, CommentFollowSerializer, HotTucaoSerializer, TucaoIndexSerializer
from tucao.utils import add_signature, generate_AnonymousUserName

logger = logging.getLogger('django')


# url(r'^tucaos/$',views.TucaoView.as_view()),
class TucaoViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, GenericViewSet):
    """吐槽列表和吐槽发布视图"""
    # 创建时间的倒序排序
    serializer_class = TucaoSerializer
    # 分页
    pagination_class = StandardResultsSetPagination

    def get(self, request):
        return self.list(request)

    def perform_authentication(self, request: Request):
        """重写验证方法,避免在登录的时候直接验证"""
        pass

    def list(self, request, *args, **kwargs):
        """重写list方法"""
        try:
            # 验证用户是否登录
            user = request.user
        except Exception as e:
            user = None
            logger.error(' AnonymousUser')

        # 过滤
        queryset = Tucao.objects.all()
        if queryset:
            queryset = queryset.order_by('-create_time')
        # 分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            # print(serializer.data)
            # print(type(serializer.data))
            if user is not None and user.is_authenticated:
                # # 如果用户是登录状态,我们将用户的的收藏的的吐槽信息查出来,并且在序列化返回的数据中插入是否收藏的标志
                # tucao_collects = Collections.objects.filter(user=user)
                # tucao_collects_id = []
                # # print(list(tucao_collects))
                # # 构造收藏的吐槽的列表
                # for tucao_select in tucao_collects:
                #     # print(tucao_select.tucao_id)
                #     tucao_collects_id.append(tucao_select.tucao_id)
                # # 便利序列化返回的数据
                # for data_dict in serializer.data:
                #     # print(data_dict.__dict__)
                #     # print(list(data_dict.items())[0][1])
                #     # list(data_dict.items())[0][1] == data_dict['id']
                #     # print(data_dict['id'])
                #     if data_dict['id'] in tucao_collects_id:
                #         # 有序字典继承与普通字典,他同样具有普通字典的方法
                #         # 插入是否收藏的标志
                #         data_dict['collect'] = True
                #     else:
                #         data_dict['collect'] = False

                # 往序列化器数据中插入是否收藏的标志
                add_signature(Collections, 'tucao_id', user, serializer, compare_attr='id', signature_name='collect')
                # 往序列化器数据中插入是否点赞的标志
                add_signature(TucaoFollow, 'tucao_id', user, serializer, compare_attr='id',
                              signature_name='spit_follow')

                # print(serializer.data)
            return self.get_paginated_response(serializer.data)
        # 序列化
        serializer = self.get_serializer(queryset, many=True)
        if user is not None and user.is_authenticated:
            add_signature(Collections, 'tucao_id', user, serializer, compare_attr='id', signature_name='collect')
            # 往序列化器数据中插入是否点赞的标志
            add_signature(TucaoFollow, 'tucao_id', user, serializer, compare_attr='id', signature_name='spit_follow')
        return Response(serializer.data)

    def post(self, request):
        return self.create(request)

    def create(self, request, *args, **kwargs):
        # 获取参数
        content = request.data.get('content', None)
        if content is None:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 判断用户是否是登录状态
        try:
            # 验证用户是否登录
            user = request.user
        except Exception as e:
            user = None
            logger.error(' AnonymousUser')

        # 保存
        # 登录直接发布
        if user is not None and user.is_authenticated:
            tucao = Tucao.objects.create(
                content=content,
                user=user,
            )
        # 未登录,生成匿名的用户名
        else:
            username = generate_AnonymousUserName()
            tucao = Tucao.objects.create(
                content=content,
                username=username,
            )

        # 序列化返回
        # # 获取序列化器
        serializer = TucaoSerializer(instance=tucao)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}


# url(r'^tucaos/(?P<pk>\d+)/$',views.TucaoRetrieveView.as_view()),
class TucaoRetrieveView(RetrieveAPIView):
    """吐槽详情视图"""
    queryset = Tucao.objects.all()
    serializer_class = TucaoDetailSerializer

    def perform_authentication(self, request: Request):
        """重写验证方法,避免在登录的时候直接验证"""
        pass

    def retrieve(self, request, *args, **kwargs):

        try:
            # 验证用户是否登录
            user = request.user
        except Exception as e:
            user = None
            logger.error(' AnonymousUser')

        instance = self.get_object()
        serializer = self.get_serializer(instance)
        # print(serializer.data)
        if user is not None and user.is_authenticated:
            # 往序列化器数据中插入是否点赞的标志
            # 从第三方表查出当前用户的数据
            signatures = TucaoFollow.objects.filter(user=user)
            # 构建当前用户数据的比较集列表
            signatures_attr_li = []
            for signature in signatures:
                # 按照传入的需要收集的比较属性,获得属性,并追加到比较集列表中
                signatures_attr_li.append(getattr(signature, 'tucao_id'))

            data = dict(serializer.data)
            # 如果当前数据的比较属性出现在比较集中,则插入True,否则False
            if data['id'] in signatures_attr_li:
                # 有序字典继承与普通字典,他同样具有普通字典的方法
                # 插入是否收藏的标志

                data['spit_follow'] = True
            else:
                data['spit_follow'] = False
            # print(data)
            return Response(data)
        else:
            return Response(serializer.data)


# url(r'^tucaos/(?P<tucao_id>\d+)/comments/$',views.TucaoCommentListView.as_view()),
class TucaoCommentViewSet(mixins.ListModelMixin, mixins.CreateModelMixin, GenericViewSet):
    """吐槽评论试图"""

    serializer_class = CommentSerializer
    # 分页
    pagination_class = StandardResultsSetPagination

    def perform_authentication(self, request: Request):
        """重写验证方法,避免在登录的时候直接验证"""
        pass

    @action(methods=['get'], detail=False)
    def list(self, request, *args, **kwargs):
        """重写list方法"""
        try:
            # 验证用户是否登录
            user = request.user
        except Exception as e:
            user = None
            logger.error(' AnonymousUser')

        # 过滤
        tucao_id = self.kwargs['tucao_id']
        queryset = Comment.objects.filter(tucao_id=tucao_id)
        if queryset:
            queryset = queryset.order_by('-create_time')
        # 分页
        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            # print(serializer.data)
            if user is not None and user.is_authenticated:
                # 往序列化器数据中插入是否点赞的标志
                add_signature(CommentFollow, 'comment_id', user, serializer, compare_attr='id',
                              signature_name='comment_follow')

                # print(serializer.data)
            return self.get_paginated_response(serializer.data)
        # 序列化
        serializer = self.get_serializer(queryset, many=True)
        if user is not None and user.is_authenticated:
            # 往序列化器数据中插入是否点赞的标志
            add_signature(CommentFollow, 'comment_id', user, serializer, compare_attr='id',
                          signature_name='comment_follow')
        return Response(serializer.data)

    @action(methods=['post'], detail=False)
    def create(self, request, *args, **kwargs):
        # 获取参数
        tucao_id = self.kwargs.get('tucao_id', None)
        content = request.data.get('content', None)
        parent_id = request.data.get('parent_id', None)

        args_dict = {}  # 用于构造参数字典
        parent = ''

        # 校验是父平路还是子评论
        if parent_id is not None:
            parent = Comment.objects.get(id=parent_id)

        if parent:
            args_dict['parent'] = parent

        if not (content or tucao_id):
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 校验当前吐槽是否存在
        tucao = Tucao.objects.get(id=tucao_id)

        if not tucao:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        # 判断用户是否是登录状态
        try:
            # 验证用户是否登录
            user = request.user
        except Exception as e:
            user = None
            logger.error(' AnonymousUser')

        # 保存
        # 登录直接发布
        if user is not None and user.is_authenticated:
            comment = Comment.objects.create(
                content=content,
                user=user,
                tucao=tucao,
                **args_dict,
            )
        # 未登录,生成匿名的用户名
        else:
            username = generate_AnonymousUserName()
            comment = Comment.objects.create(
                content=content,
                username=username,
                tucao=tucao,
                **args_dict,
            )

        # 评论数+1
        tucao.comment_count += 1
        tucao.save()

        # 序列化返回
        # # 获取序列化器
        serializer = CommentSerializer(instance=comment)
        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def get_success_headers(self, data):
        try:
            return {'Location': str(data[api_settings.URL_FIELD_NAME])}
        except (TypeError, KeyError):
            return {}


# url(r'^tucaos/follows/$',views.TucaoFollowView.as_view()),
class TucaoFollowView(APIView):
    """吐槽点赞视图"""
    permission_classes = [IsAuthenticated]

    def post(self, request: Request):
        # 获取参数
        tucao_id = request.data.get('tucao_id', None)
        action = request.data.get('action', None)
        # print(action)
        if not tucao_id:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        if action not in ['follow', 'unfollow']:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        user = request.user
        tucao = Tucao.objects.filter(id=tucao_id).first()
        # 校验参数
        if not all([user, tucao]):
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if action == 'follow':
            # 查询数据库
            tucao_follow = TucaoFollow.objects.filter(tucao=tucao, user=user)
            if tucao_follow:
                return Response({'message': '不能重复点赞'}, status=status.HTTP_400_BAD_REQUEST)
            tucao_follow = TucaoFollow.objects.create(
                user=user,
                tucao=tucao,
            )
            # 更新点赞数
            tucao.follow_count += 1
            tucao.save()

            serializer = TucaoFollowSerializer(tucao_follow)

            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            tucao_follow = TucaoFollow.objects.filter(tucao=tucao, user=user)
            if not tucao_follow:
                return Response({'message': '未点赞'}, status=status.HTTP_400_BAD_REQUEST)
            tucao_follow.delete()

            # 更新点赞数
            tucao.follow_count -= 1
            tucao.save()

            return Response({'tucao_follow': '取消点赞成功'}, status.HTTP_204_NO_CONTENT)


# url(r'^tucaos/collections/$',views.TucaoCollectView.as_view()),
class TucaoCollectView(APIView):
    """吐槽收藏视图"""
    permission_classes = [IsAuthenticated]

    def post(self, request: Request):
        # 获取参数
        tucao_id = request.data.get('tucao_id', None)
        action = request.data.get('action', None)
        if not tucao_id:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        if action not in ['collect', 'uncollect']:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        user = request.user
        tucao = Tucao.objects.filter(id=tucao_id).first()
        # 校验参数
        if not all([user, tucao]):
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if action == 'collect':
            # 查询数据库
            tucao_collect = Collections.objects.filter(tucao=tucao, user=user)
            if tucao_collect:
                return Response({'message': '不能重复收藏'}, status=status.HTTP_400_BAD_REQUEST)
            tucao_collect = Collections.objects.create(
                user=user,
                tucao=tucao,
            )

            serializer = TucaoSelectSerializer(tucao_collect)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            tucao_collect = Collections.objects.filter(tucao=tucao, user=user)
            if not tucao_collect:
                return Response({'message': '未收藏'}, status=status.HTTP_400_BAD_REQUEST)
            tucao_collect.delete()

            return Response({'tucao_collect': '取消收藏成功'}, status.HTTP_204_NO_CONTENT)


# url(r'^tucaos/comments/follows/$',views.CommentFollowView.as_view()),
class CommentFollowView(APIView):
    """评论点赞视图"""
    permission_classes = [IsAuthenticated]

    def post(self, request: Request):
        # 获取参数
        comment_id = request.data.get('comment_id', None)
        tucao_id = request.data.get('tucao_id', None)
        action = request.data.get('action', None)
        if not all([tucao_id, comment_id]):
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        if action not in ['follow', 'unfollow']:
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)
        user = request.user
        comment = Comment.objects.filter(id=comment_id).first()
        tucao = Tucao.objects.filter(id=tucao_id).first()
        # 校验参数
        if not all([user, tucao, comment]):
            return Response({'message': '参数错误'}, status=status.HTTP_400_BAD_REQUEST)

        if action == 'follow':
            # 查询数据库
            comment_follow = CommentFollow.objects.filter(tucao=tucao, user=user, comment=comment)
            if comment_follow:
                return Response({'message': '不能重复点赞'}, status=status.HTTP_400_BAD_REQUEST)
            comment_follow = CommentFollow.objects.create(
                user=user,
                tucao=tucao,
                comment=comment,
            )
            # 更新点赞数
            comment.count += 1
            comment.save()

            serializer = CommentFollowSerializer(comment_follow)
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        else:
            comment_follow = CommentFollow.objects.filter(tucao=tucao, user=user, comment=comment)
            if not comment_follow:
                return Response({'message': '未点赞'}, status=status.HTTP_400_BAD_REQUEST)
            comment_follow.delete()

            # 更新点赞数
            # 更新点赞数
            comment.count -= 1
            comment.save()

            return Response({'comment_follow': '取消点赞成功'}, status.HTTP_204_NO_CONTENT)


# url(r'^tucaos/hots/$',views.HotTucaoView.as_view()),
class HotTucaoView(ListAPIView):
    queryset = Tucao.objects.all().order_by('-follow_count')[0:4]
    serializer_class = HotTucaoSerializer


class TucaoSearchViewSet(HaystackViewSet):
    '''搜索'''
    index_models = [Tucao]

    serializer_class = TucaoIndexSerializer

    pagination_class = StandardResultsSetPagination
